use core::sync::atomic::Ordering;

use private::{AtomicWifiAccessPointState, AtomicWifiStationState};
pub use private::{WifiAccessPointState, WifiStationState};

use super::WifiEvent;

mod private {
    use portable_atomic_enum::atomic_enum;

    /// Wi-Fi interface for station state.
    #[atomic_enum]
    #[derive(PartialEq, Debug)]
    #[cfg_attr(feature = "defmt", derive(defmt::Format))]
    #[non_exhaustive]
    pub enum WifiStationState {
        /// Station started.
        Started,
        /// Station connected.
        Connected,
        /// Station disconnected.
        Disconnected,
        /// Station stopped
        Stopped,
        /// Invalid state.
        Invalid,
    }

    /// Wi-Fi interface for access point state.
    #[atomic_enum]
    #[derive(PartialEq, Debug)]
    #[cfg_attr(feature = "defmt", derive(defmt::Format))]
    #[non_exhaustive]
    pub enum WifiAccessPointState {
        /// Access point started.
        Started,
        /// Access point stopped.
        Stopped,
        /// Invalid state.
        Invalid,
    }
}

impl From<WifiEvent> for WifiStationState {
    fn from(event: WifiEvent) -> WifiStationState {
        match event {
            WifiEvent::StationStart => WifiStationState::Started,
            WifiEvent::StationConnected => WifiStationState::Connected,
            WifiEvent::StationDisconnected => WifiStationState::Disconnected,
            WifiEvent::StationStop => WifiStationState::Stopped,
            _ => WifiStationState::Invalid,
        }
    }
}

impl From<WifiEvent> for WifiAccessPointState {
    fn from(event: WifiEvent) -> WifiAccessPointState {
        match event {
            WifiEvent::AccessPointStart => WifiAccessPointState::Started,
            WifiEvent::AccessPointStop => WifiAccessPointState::Stopped,
            _ => WifiAccessPointState::Invalid,
        }
    }
}

pub(crate) static STATION_STATE: AtomicWifiStationState =
    AtomicWifiStationState::new(WifiStationState::Invalid);
pub(crate) static ACCESS_POINT_STATE: AtomicWifiAccessPointState =
    AtomicWifiAccessPointState::new(WifiAccessPointState::Invalid);

/// Get the current state of the access point.
pub fn access_point_state() -> WifiAccessPointState {
    ACCESS_POINT_STATE.load(Ordering::Relaxed)
}

/// Get the current state of the Station.
pub fn station_state() -> WifiStationState {
    STATION_STATE.load(Ordering::Relaxed)
}

pub(crate) fn update_state(event: WifiEvent, handled: bool) {
    match event {
        WifiEvent::StationConnected
        | WifiEvent::StationDisconnected
        | WifiEvent::StationStart
        | WifiEvent::StationStop => {
            STATION_STATE.store(WifiStationState::from(event), Ordering::Relaxed)
        }

        WifiEvent::AccessPointStart | WifiEvent::AccessPointStop => {
            ACCESS_POINT_STATE.store(WifiAccessPointState::from(event), Ordering::Relaxed)
        }

        other => {
            if !handled {
                debug!("Unhandled event: {:?}", other)
            }
        }
    }
}

pub(crate) fn reset_access_point_state() {
    ACCESS_POINT_STATE.store(WifiAccessPointState::Invalid, Ordering::Relaxed)
}

pub(crate) fn reset_station_state() {
    STATION_STATE.store(WifiStationState::Invalid, Ordering::Relaxed)
}
